#pragma once

#include "../camera/Camera.hpp"
#include "../camera/TargetCamera.hpp"
#include "../model/ModelLayer.hpp"
#include "../skybox/SkyBox.hpp"
#include "../material/Material.hpp"

class Scene {

	friend class Engine;

private:

	Fog fog;
	
private:

	std::set <Light*> lightSet;
	
public:

	void attachLight(Light* light);
	
	void detachLight(Light* light);
	
	void detachAllLight();
	
private:

	SkyBox* skyBox = &defaultSkyBox;
	
public:

	void setSkyBox(SkyBox* skyBox);
	
private:

	bool playFlag = false;

	bool pauseFlag = false;

	bool drawFlag = false;
	
public:

	const bool isPause() const;
	
	const bool isPlay() const;

	void play();
	
	void stop();
	
	void quit();
	
	void redraw();
	
public:

	virtual void onPause(){}

	virtual void onResume(){}
	
	virtual void onPlay(){}
	
	virtual void onStop(){}

	virtual void onFrame(){}
	
	virtual void onFps(unsigned int fps){}

protected:

	std::map <GLuint, ModelLayer*> layerMap;
	
public:

	ModelLayer& layer(const GLuint layerName);
	
	void eraseLayer(const GLuint layerName);
	
	void eraseAllLayers();
	
private:

	Camera* camera = &defaultCamera;
	
public:

	void setCamera(Camera* camera);
	
protected:

	void draw();

public:
	
	virtual ~Scene();
	
};

void Scene::draw(){
	for (auto it = layerMap.begin(); it != layerMap.end(); ++it)
		(*it).second->draw();
}

Scene::~Scene(){
	eraseAllLayers();
}

void Scene::setCamera(Camera* camera){
	Scene::camera = camera ? camera : &defaultCamera;
}

ModelLayer& Scene::layer(const GLuint layerName){
	auto it = layerMap.find(layerName);
	if (it != layerMap.end())
		return *(*it).second;
	ModelLayer* layer = new ModelLayer();
	layerMap[layerName] = layer;
	return *layer;
}

void Scene::eraseLayer(const GLuint layerName){
	for (auto it = layerMap.begin(); it != layerMap.end(); it++)
		if ((*it).first == layerName) {
			delete (*it).second;
			layerMap.erase(it);
		}
}

void Scene::eraseAllLayers(){
	for (auto it = layerMap.begin(); it != layerMap.end(); ++it)
		delete (*it).second;
	layerMap.clear();
}

const bool Scene::isPause() const {
	return pauseFlag;
}

void Scene::redraw(){
	drawFlag = true;
}

const bool Scene::isPlay() const {
	return playFlag;
}

void Scene::play(){
	engine.play(this);
}

void Scene::stop(){
	playFlag = false;
}

void Scene::quit(){
	engine.quit();
}

void Scene::setSkyBox(SkyBox* skyBox){
	Scene::skyBox = skyBox ? skyBox : &defaultSkyBox;
}

void Scene::attachLight(Light* light){
	if (light) 
		lightSet.insert(light);
}
	
void Scene::detachLight(Light* light){
	lightSet.erase(light);
}
	
void Scene::detachAllLight(){
	lightSet.clear();
}
